﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using Import;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Document = iTextSharp.text.Document;
using Font = iTextSharp.text.Font;

namespace Web.Helpers.Documents.Scripts
{
    public class STR : IScriptDocument
    {
        public class StrSummaryInfo
        {
            #region Properties
            public MemoryStream Stream { get; set; }
            public Document Document { get; set; }
            public PdfWriter Writer { get; set; }
            public STR Str { get; set; }
            #endregion

            #region Constructors
            public StrSummaryInfo(STR str, Dictionary<string, CharacterInfo> charactersInfo)
            {
                this.Str = str;
                this.Str.TotalCount.CharactersInfo = charactersInfo;

                this.Document = new Document(PageSize.LETTER);
                this.Document.SetMargins(25, 25, 25, 25);

                this.Stream = new MemoryStream();
                this.Writer = PdfWriter.GetInstance(this.Document , this.Stream);
                this.Writer.InitialLeading = InitialLeading; //spacing between lines

                this.Document.Open();
            }
            #endregion

            #region Public Methods
            public void Create()
            {
                this.Document.SetMargins(25, 25, 25, 25);
                this.Document.NewPage();
                this.Document.SetMargins(25, 25, 25, 25);
                CreateSourceDocumentInfoAndTotalsTable();
                CreateCharactersInfoTable();
            }
            public void Dispose()
            {
                this.Writer.Flush();
                this.Writer.CloseStream = false;
                this.Document.Close();                
            }
            #endregion

            #region Private Methods
            private void CreateSourceDocumentInfoAndTotalsTable()
            {
                var cellWidths = new float[5] { 20, 50, 2, 18, 10 };
                var table = new PdfPTable(cellWidths.Length) { WidthPercentage = 100, SpacingBefore = 15f, SpacingAfter = 0f };
                    table.SetWidths( cellWidths );

                    table.TotalWidth = 550;
                    table.LockedWidth = true;

                var headerCellStyle = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Normal },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left }
                };

                var borderlessCellStyle = new PdfHelper.CellStyle()
                {
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } }
                };

                var pdfHelper = new PdfHelper();

                    pdfHelper.AddCell(table, "Proyecto".ToUpper(), headerCellStyle);
                    //pdfHelper.AddCell(table, this.Str.SourceDocument.Keyword.ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.SourceDocument.Project.ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, "", borderlessCellStyle);
                    pdfHelper.AddCell(table, "Duración".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.SourceDocument.RunningTime.ToUpper(), headerCellStyle);


                    pdfHelper.AddCell(table, "Título Original".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.SourceDocument.OriginalTitle.ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, "", borderlessCellStyle);
                    pdfHelper.AddCell(table, "Páginas".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.TotalCount.PageCount.ToString(), headerCellStyle);

                    pdfHelper.AddCell(table, "Título Español".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.SourceDocument.TranslatedTitle.ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, "", borderlessCellStyle);
                    pdfHelper.AddCell(table, "Loops".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.TotalCount.CharactersInfo.Sum(x => x.Value.Loops).ToString(), headerCellStyle);

                    pdfHelper.AddCell(table, "Traducción".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.SourceDocument.Translator.ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, "", borderlessCellStyle);
                    pdfHelper.AddCell(table, "Personajes".ToUpper(), headerCellStyle);
                    pdfHelper.AddCell(table, this.Str.TotalCount.CharactersInfo.Count.ToString(), headerCellStyle);

                this.Document.Add( table );
            }
            private void CreateCharactersInfoTable()
            {
                var cellWidths = new float[6] { 30, 10, 10, 28, 12, 10};

                var table = new PdfPTable(cellWidths.Length) { WidthPercentage = 100, SpacingBefore = 15f, SpacingAfter = 0f };
                    table.SetWidths( cellWidths );

                    table.TotalWidth = 550f;
                    table.LockedWidth = true;

                var fullRowHeaderMainTitleCellStyle = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 18, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center },
                    Span = new PdfHelper.CellStyle.CellSpan() { Cols = 6 },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Left = 1f, Top = 1f, Bottom = 0f, Right = 1f } }
                };
                var fullRowHeaderSubTitleCellStyle = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Normal },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center },
                    Span = new PdfHelper.CellStyle.CellSpan() { Cols = 6 },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Left = 1f, Top = 0f, Bottom = 1f, Right = 1f } }
                };

                //var fullRowHeaderCellStyle2 = new PdfHelper.CellStyle()
                //{
                //    Font = new PdfHelper.CellStyle.CellFont() { Size = 18, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                //    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 15, Left = 5, Right = 5, Top = 15 },
                //    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center },
                //    Span = new PdfHelper.CellStyle.CellSpan() { Cols = 6 },
                //    Border = new PdfHelper.CellStyle.BorderStyle() { Width = 1 }
                //};

                var headerCellStyle = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center }
                };
                
                var rowCellStyleLeft = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Normal },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left }
                };
                var rowCellStyleCentered = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Normal },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center }
                };
                var rowCellStyleCenteredInBold = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 10, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center }
                };

                var pdfHelper = new PdfHelper();

                //var mainTitle = String.Format("{0} - EP. {1}", this.Str.SourceDocument.OriginalTitle.ToUpper(), this.Str.SourceDocument.Episode);
                var mainTitle = String.Format("{0} - EP. {1}", this.Str.SourceDocument.Project.ToUpper(), this.Str.SourceDocument.Episode.ToUpper());
                var subTitle = String.Format("{0}", this.Str.SourceDocument.TranslatedTitle.ToUpper());
                pdfHelper.AddCell(table, mainTitle , fullRowHeaderMainTitleCellStyle);
                pdfHelper.AddCell(table, subTitle, fullRowHeaderSubTitleCellStyle);

                pdfHelper.AddCell(table, "Personaje".ToUpper(), headerCellStyle);
                pdfHelper.AddCell(table, "".ToUpper(), headerCellStyle);
                pdfHelper.AddCell(table, "Col".ToUpper(), headerCellStyle);
                pdfHelper.AddCell(table, "Actor".ToUpper(), headerCellStyle);
                pdfHelper.AddCell(table, "Llamado".ToUpper(), headerCellStyle);
                pdfHelper.AddCell(table, "Loops".ToUpper(), headerCellStyle);

                var timeCodeFormat = TimeCode.GetCorrespondingFormat(this.Str.TotalCount.CharactersInfo.Values.SelectMany(x => x.TimeCodes).ToList());

                var characters              = this.Str.TotalCount.CharactersInfo;
                var mainCharacters          = characters.OrderByDescending(x => x.Value.Loops).Take(BRK.MainCharactersSize).ToDictionary(x => x.Key, x => x.Value);
                var additionalCharacters    = characters.Except( mainCharacters ).OrderByDescending(x => x.Value.Loops).ToDictionary(x => x.Key, x => x.Value);

                foreach (var character in this.Str.TotalCount.CharactersInfo)
                {
                    var columnInfo = GetCharacterColumnInfo(mainCharacters, additionalCharacters, character.Key);

                    pdfHelper.AddCell(table, character.Key.ToUpper(), rowCellStyleLeft);
                    pdfHelper.AddCell(table, character.Value.TimeCodes.First().ToString(timeCodeFormat), rowCellStyleCentered);
                    pdfHelper.AddCell(table, columnInfo.ToUpper(), rowCellStyleCenteredInBold);
                    pdfHelper.AddCell(table, "", rowCellStyleLeft);
                    pdfHelper.AddCell(table, "", rowCellStyleLeft);
                    pdfHelper.AddCell(table, character.Value.Loops.ToString(), rowCellStyleCenteredInBold);
                }

                this.Document.Add( table );
            }
            #endregion
        }

        private static string GetCharacterColumnInfo(Dictionary<string, CharacterInfo> mainCharacters, Dictionary<string, CharacterInfo> additionalCharacters, string characterName)
        {
            var columnInfo = String.Empty;
            var arrMainChars = mainCharacters.ToArray();
            var arrAdditionalChars = additionalCharacters.ToArray();
            if (mainCharacters.ContainsKey(characterName))
            {
                for (var i = 0; i < arrMainChars.Count(); i++)
                {
                    if (arrMainChars[i].Key == characterName)
                    {
                        columnInfo = String.Format("COL {0}", i+1);
                        break;
                    }
                }
            }
            else
            {
                for (var i = 0; i < arrAdditionalChars.Count(); i++)
                {
                    if (arrAdditionalChars[i].Key == characterName)
                    {
                        columnInfo = String.Format("ADC {0}", i +1 + BRK.MainCharactersSize);
                        break;
                    }
                }                        
            }
            return columnInfo;
        }

        public StrSummaryInfo SummaryPage { get; set; }

        public MemoryStream Stream { get; set; }
        public Document Document { get; set; }
        public PdfWriter Writer { get; set; }

        public SourceDocumentInfo SourceDocument { get; set; }

        public class TotalCountInfo
        {
            public Dictionary<string, CharacterInfo> CharactersInfo { get; set; }
            public int PageCount { get; set; }
        }
        public TotalCountInfo TotalCount { get; set; }

        public Font TimeCodeFont { get; set; }
        public Font CharacterFont { get; set; }
        public Font DialogueFont { get; set; }

        public bool IsFirstDialogueOnPage { get; set; }
       
        public int TotalLoops { get; set; }

        public class LoopBoundaryLineInfo
        {
            public float PositionX { get; set; }    
            public float PositionY { get; set; }
            public int PageNumber { get; set; }
        }
        public LoopBoundaryLineInfo LastLoopBoundaryDrawed { get; set; }
        public List<LoopBoundaryLineInfo> LastLoopBoundariesDrawed { get; set; }

        public class LoopPositionInfo
        {
            public int Page { get; set; }
            public float Position { get; set; }
            public float FirstWordPosition { get; set; }
        }
        public LoopPositionInfo LoopPosition { get; set; }

        public Dictionary<TimeCode, int> TimeCodes { get; set; }

        public Dictionary<string, string> PdfSpecialCharAndReplacements = new Dictionary<string, string>() { { "…", "..."}, {"-", "–"} };

        #region Constants

        public const int WordsPerLoop = 25;
        public const int MarginLeft = 72;
        public const int MarginRight = 32;
        public const int MarginTop = 25;
        public const int MarginBottom = 40;
        public const int InitialLeading = 28;

        public const int OffsetTop     = 4;
        public const int OffsetBottom  = 8;
        public const int OffsetLeft    = 1;
        public const int OffsetRight   = 1;
        public const int LoopNumberXPos = 20;

        #endregion

        private ImportSettings ImportSettings { get; set; }
        private string AnnotationStart { get; set; }
        private string AnnotationEnd { get; set; }

        public STR(ImportSettings importSettings, string translator, string project, string episode, string originalTitle, string translatedTitle, string runningTime)
        {
            this.ImportSettings     = importSettings;
            var annotations         = this.ImportSettings.Annotations[ImportSettings.ImportAnnotations.Director];
            this.AnnotationStart    = annotations[0];
            this.AnnotationEnd      = annotations[1];

            this.Stream = new MemoryStream();
            this.Document = new Document(PageSize.LETTER);
            this.Document.SetMargins(MarginLeft, MarginRight, MarginTop, MarginBottom);

            this.TimeCodes = new Dictionary<TimeCode, int>();
            this.LoopPosition = new LoopPositionInfo();

            this.SourceDocument = new SourceDocumentInfo()
            {
                RunningTime = runningTime,
                Project = project,
                Episode = episode,
                OriginalTitle = originalTitle,
                TranslatedTitle = translatedTitle,
                Translator = translator
            };

            this.TotalCount = new TotalCountInfo();

            FontFactory.RegisterDirectories();
            this.TimeCodeFont = FontFactory.GetFont("Arial", 13f, Font.NORMAL, new BaseColor(Color.Black));
            this.CharacterFont = FontFactory.GetFont("Arial", 13f, Font.BOLD, new BaseColor(Color.Black));
            this.DialogueFont = FontFactory.GetFont("Arial", 13f, Font.NORMAL, new BaseColor(Color.Black));

            //SetCharacterSpacing(1);

            this.Writer = PdfWriter.GetInstance(this.Document, this.Stream);
            this.Writer.PageEvent = new StrPageEvent(this);
            this.Writer.InitialLeading = InitialLeading; //spacing between lines
            
            this.Document.Open();

            CreateSummaryTable();
        }

        private void CreateSummaryTable()
        {
            var widths = new float[2] {25, 75};
            var tblHeader = new PdfPTable(widths.Length) { WidthPercentage = 100, SpacingBefore = 15f, SpacingAfter = 0f };
                tblHeader.SetWidths( widths );

            var headerCellStyle = new PdfHelper.CellStyle()
            {
                Font = new PdfHelper.CellStyle.CellFont() { Size = 11, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                Padding = new PdfHelper.CellStyle.CellPadding() { Bottom = 5, Left = 5, Right = 5, Top = 5 },
                Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left }
            };

            var pdfHelper = new PdfHelper();

            pdfHelper.AddCell(tblHeader, "Traducción".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.Translator.ToUpper(), headerCellStyle);
            //pdfHelper.AddCell(tblHeader, "Clave".ToUpper(), headerCellStyle);
            //pdfHelper.AddCell(tblHeader, this.SourceDocument.Keyword.ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, "Proyecto".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.Project.ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, "Nro. Episodio".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.Episode.ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, "Título Original".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.OriginalTitle.ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, "Título Español".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.TranslatedTitle.ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, "Duración".ToUpper(), headerCellStyle);
            pdfHelper.AddCell(tblHeader, this.SourceDocument.RunningTime.ToUpper(), headerCellStyle);

            this.Document.Add( tblHeader );            
        }

        //public int GetLoopPageNumber(string timeCode)
        //{
        //    return this.TimeCodes.FirstOrDefault(x => x.Key == timeCode).Value;
        //}
        public static int GetLoopPageNumber(Dictionary<string, int> timeCodes, string timeCode)
        {
            return timeCodes.FirstOrDefault(x => x.Key == timeCode).Value;
        }

        public void CreateSummaryPage(Dictionary<string, CharacterInfo> characters)
        {
            this.SummaryPage = new StrSummaryInfo(this, characters);
            this.SummaryPage.Create();
            this.SummaryPage.Dispose();
        }

        public void SaveToFile(string path, string filename)
        {
            filename = FileHelper.GetSafeFilename(path, filename);
            //var fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write);
            //this.Writer.Flush();
            //this.Writer.CloseStream = false;
            //this.Document.Close();
            //this.Stream.Position = 0;
            //this.Stream.WriteTo( fileStream );
            //    fileStream.Close();
            //this.Stream.Close();

            // TODO => hack as OnCloseDocument triggers, but does not write anything because it seems to be stepped on Current (Last) Page +1, which does not exist
            var strPageEvent = (StrPageEvent)this.Writer.PageEvent;
                strPageEvent.OnFinalPage(this.Writer, this.Document);

            this.Writer.Flush();
            this.Writer.CloseStream = false;

            this.Document.Close();

            var contents = new List<byte[]> { this.SummaryPage.Stream.ToArray(), this.Stream.ToArray() };

            PdfHelper.CombinePDFs(filename, contents);
        }

        public class StrPageEvent : PdfPageEventHelper
        {
            #region Properties

            public int WordCount { get; set; }
            public int LoopCount { get; set; }
            
            public TimeCode CurrentTimeCode { get; set; }
            public TimeCode LastTimeCode { get; set; }
            public TimeCode CarriedTimeCode { get; set; }
            public TimeCode IgnoredTimeCode { get; set; }

            public STR Str { get; set; }

            //PdfContentByte cb;
            //PdfTemplate template;

            #endregion

            #region Constructors

            public StrPageEvent(STR str)
            {
                this.Str = str;
            }

            #endregion

            #region Private Methods

            private void CheckForLoopByAmountOfWords(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, TimeCode timeCode, string word, bool doNotZigZag)
            {
                if ( !this.Str.ImportSettings.LoopParsers.ContainsKey(ImportSettings.LoopParserTypes.ByWords) )
                    return;

                var wordsForLoop = this.Str.ImportSettings.LoopParsers[ImportSettings.LoopParserTypes.ByWords];

                var offsetX = 0f;
                
                //Remove annotations
                word = ScriptHelper.RemoveAnnotations(word, this.Str.AnnotationStart, this.Str.AnnotationEnd);

                //Remove special chars
                word = ScriptHelper.ReplaceSpecialChars(word, ScriptHelper.SpecialChars, " ");
                word = ScriptHelper.RemoveExtraWhitespaces(word);

                word = word.Trim();
                var wordsFound = word.Split(' ');

                //Only if all chars within word are special chars, then omit
                var omit = word.All(chr => ScriptHelper.SpecialChars.Contains(chr.ToString()));
                if ( omit )
                    return;

                //this.WordCount++;
                //this.WordCount += wordsFound.Length;
                this.WordCount += 1;

                if ( this.WordCount == wordsForLoop )
                {
                    this.LoopCount++;
                    this.Str.TotalLoops = this.LoopCount;

                    var currentPageNumber   = this.Str.Writer.PageNumber;

                    if (this.Str.LoopPosition.Page == 0 && this.Str.LoopPosition.Position <= 0 )
                    {
                        this.Str.LoopPosition.Page      = currentPageNumber;
                        this.Str.LoopPosition.Position  = this.Str.LoopPosition.FirstWordPosition;
                    }
                    if (this.Str.LoopPosition.Page != currentPageNumber)
                        this.Str.LoopPosition.Position = this.Str.LoopPosition.FirstWordPosition;

                    #region Loop found on combined word
                    //Only when loop is found and word in a combined word (i.e. coca-cola)
                    if ( wordsFound.Length > 1 )
                    {
                        doNotZigZag = false;

                        var letterSize = rect.Width / String.Join(" ", wordsFound).Length;
                        var fullWordLength = word.Length;
                        var currentWordLength = wordsFound[0].Length;
                        offsetX = - ( (fullWordLength - currentWordLength) * letterSize );
                    }
                    #endregion

                    var currentYPosition    = rect.Bottom;
                    this.Str.DrawLoopBoundaryLine(writer, document, rect, doNotZigZag, offsetX);
                    this.Str.DrawLoopNumber(writer, this.LoopCount, this.Str.LoopPosition.Position, currentYPosition);

                    this.Str.LoopPosition = new LoopPositionInfo() { Page = currentPageNumber, Position = currentYPosition };

                    this.ResetWordCount();
                    this.ResetTimeCount();

                    this.IgnoredTimeCode = timeCode;
                }

                if ( wordsFound.Length > 1 )
                {
                    var arrWords = word.Split(' ');
                    word = String.Empty;
                    for (var i = 0; i < arrWords.Length-1; i++)
                    {
                        word += arrWords[i+1] + " ";
                    }
                    CheckForLoopByAmountOfWords(writer, document, rect, timeCode, word, doNotZigZag);
                }
            }
            private void CheckForLoopByAmountOfTime(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, TimeCode timeCode)
            {
                this.CurrentTimeCode = timeCode;

                if ( this.CarriedTimeCode.IsNull() )
                    this.CarriedTimeCode = this.CurrentTimeCode;

                if ( !this.Str.ImportSettings.LoopParsers.ContainsKey(ImportSettings.LoopParserTypes.ByTime) )
                    return;

                var timeForLoop = this.Str.ImportSettings.LoopParsers[ImportSettings.LoopParserTypes.ByTime];

                if ( TimeCode.AreEqual(this.CurrentTimeCode, this.IgnoredTimeCode) )
                    return;

                if ( this.IgnoredTimeCode.IsNotNull() && ( TimeCode.AreEqual(this.IgnoredTimeCode, this.LastTimeCode) ) )
                {
                    this.IgnoredTimeCode = null;    
                    this.CarriedTimeCode = this.CurrentTimeCode;
                }

                var elapsedSeconds = ScriptHelper.GetElapsedTime(this.CarriedTimeCode, this.CurrentTimeCode);
                if (elapsedSeconds >= timeForLoop)
                {
                    this.LoopCount++;
                    this.Str.TotalLoops = this.LoopCount;

                    var currentPageNumber   = this.Str.Writer.PageNumber;

                    if (this.Str.LoopPosition.Page == 0 && this.Str.LoopPosition.Position <= 0 )
                    {
                        this.Str.LoopPosition.Page      = currentPageNumber;
                        this.Str.LoopPosition.Position  = this.Str.LoopPosition.FirstWordPosition;
                    }
                    if (this.Str.LoopPosition.Page != currentPageNumber)
                        this.Str.LoopPosition.Position = this.Str.LoopPosition.FirstWordPosition;

                    //var currentYPosition = writer.GetVerticalPosition(false);
                    var currentYPosition    = rect.Bottom;
                    this.Str.DrawLoopBoundaryLine2(writer, document, rect);
                    this.Str.DrawLoopNumber(writer, this.LoopCount, this.Str.LoopPosition.Position, currentYPosition, true);

                    this.Str.LoopPosition = new LoopPositionInfo() { Page = currentPageNumber, Position = currentYPosition };

                    this.ResetWordCount();
                    this.ResetTimeCount();
                }

                this.LastTimeCode = this.CurrentTimeCode;
            }
            
            private void ResetTimeCount()
            {
                this.CurrentTimeCode = null;
                this.CarriedTimeCode = null;
            }
            private void ResetWordCount()
            {
                this.WordCount = 0;                
            }

            #endregion

            #region Events

            public override void OnOpenDocument(PdfWriter writer, Document document)
            {
                try
                {
                    //this.cb = writer.DirectContent;
                    //this.template = cb.CreateTemplate(50, 50);
                }
                catch (DocumentException)
                {
                }
                catch (IOException)
                {
                }
            }

            public override void OnCloseDocument(PdfWriter writer, Document document)
            {
                try
                {
                    base.OnCloseDocument(writer, document);

                    //var font = this.Str.DialogueFont;
                    //var text = String.Format("TRADUCCIÓN: {0}", this.Str.SourceDocument.Translator.ToUpper());
                    
                    //template.BeginText();
                    //template.SetFontAndSize(font.BaseFont, font.Size);
                    //template.SetTextMatrix(0, 0);
                    
                    //template.NewlineShowText("A");
                    //template.NewlineText();
                    //template.ShowText("FIN");
                    //template.NewlineText();
                    //template.ShowText(text);

                    //template.EndText();

                    ////var font2 = this.Str.DialogueFont;
                    ////document.Add( new Chunk( Environment.NewLine) );  
                    ////document.Add( new Chunk( "FIN", font2) );
                    ////document.Add( new Chunk( String.Format("TRADUCCIÓN: {0}", this.Str.SourceDocument.Translator.ToUpper()), font2) ) ;

                    //var text = String.Format("TRADUCCIÓN: {0}", this.Str.SourceDocument.Translator.ToUpper());
                    //var font = FontFactory.GetFont("Arial", 13f, Font.NORMAL, new BaseColor(Color.Black));
                
                    //canvas.BeginText();
                    //canvas.SetFontAndSize(font.BaseFont, 13);
                
                    //canvas.ShowText(text);
                    //canvas.NewlineShowText(text);
                    //canvas.ShowTextAligned(PdfContentByte.ALIGN_LEFT, text, document.PageSize.GetLeft(40), document.PageSize.GetBottom(25), 0);

                    //canvas.EndText(); 

                    ////var font = this.Str.DialogueFont;
                    ////document.Add( new Chunk( Environment.NewLine) );  
                    ////document.Add( new Chunk( "FIN", font) );
                    ////document.Add( new Chunk( String.Format("TRADUCCIÓN: {0}", this.Str.SourceDocument.Translator.ToUpper()), font) ) ;
                }
                catch (DocumentException)
                {
                }
                catch (IOException)
                {
                }
            }

            public override void OnStartPage(PdfWriter writer, Document document)
            {
                base.OnStartPage(writer, document);

                var pageNumber = writer.PageNumber;

                if ( !this.Str.Document.IsOpen() )
                    return;

                this.Str.TotalCount.PageCount = pageNumber;

                var table = new PdfPTable(3) { WidthPercentage = 100 };

                var cellStyleLeft = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 12, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Left },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                };
                var cellStyleCenter = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 12, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Center },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                };
                var cellStyleRight = new PdfHelper.CellStyle()
                {
                    Font = new PdfHelper.CellStyle.CellFont() { Size = 12, Type = PdfHelper.CellStyle.CellFont.FontType.Bold },
                    Alignment = new PdfHelper.CellStyle.CellAlignment() { Horizontal = PdfHelper.CellStyle.CellAlignment.HorizontalAlignment.Right },
                    Border = new PdfHelper.CellStyle.BorderStyle() { Widths = new PdfHelper.TopLeftRightBottom() { Bottom = 0f, Left = 0f, Top = 0f, Right = 0f } },
                };

                var pdfHelper = new PdfHelper();
                    pdfHelper.AddCell( table, String.Empty, cellStyleLeft );
                    pdfHelper.AddCell( table, String.Format("- {0} -", pageNumber) , cellStyleCenter );
                    pdfHelper.AddCell( table, String.Format("{0} - EP. {1}", this.Str.SourceDocument.Project.ToUpper(), this.Str.SourceDocument.Episode.ToUpper() ), cellStyleRight );

                this.Str.Document.Add( table );

                var canvas = writer.DirectContent;
                    canvas.SaveState();
                    canvas.SetLineWidth(0.5f);
                    canvas.MoveTo(document.Left, document.Top - 18);
                    canvas.LineTo(document.Right, document.Top - 18);
                    canvas.Stroke();
                    canvas.RestoreState();

                this.Str.IsFirstDialogueOnPage = true;
            }

            public void OnFinalPage(PdfWriter writer, Document document)
            {
                var font = this.Str.DialogueFont;
                document.Add( new Chunk( Environment.NewLine) ); 
                document.Add( new Chunk( "FIN", font) );
                document.Add( new Chunk( Environment.NewLine) );
                document.Add( new Chunk( String.Format("TRADUCCIÓN: {0}", this.Str.SourceDocument.Translator.ToUpper()), font) );
            }

            public override void OnEndPage(PdfWriter writer, Document document)
            {
                base.OnEndPage(writer, document);

                var canvas = writer.DirectContent;

                canvas.BeginText();
                canvas.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 8);
                canvas.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "Para uso exclusivo de Caja de Ruidos", document.PageSize.GetLeft(20), document.PageSize.GetBottom(15), 0);
                canvas.EndText();
            }

            public override void OnGenericTag(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, String text)
            {
                var data                = text.Split('|');
                var word                = data[0];
                var timeCode            = new TimeCode( data[1]);
                var isLineLastWord      = Convert.ToBoolean(data[2]);
                var isDialogueLastWord  = Convert.ToBoolean(data[3]);
                var isScriptLastWord    = Convert.ToBoolean(data[4]);

                var doNotZigZag = isDialogueLastWord || isLineLastWord;

                //var currentPageNumber   = this.Str.Writer.PageNumber;
                //if ( !this.Str.TimeCodes.ContainsKey( timeCode ) )                    
                //    this.Str.TimeCodes.Add( timeCode, currentPageNumber );

                var wordsForLoop = 0;
                if ( this.Str.ImportSettings.LoopParsers.ContainsKey(ImportSettings.LoopParserTypes.ByWords) )
                    wordsForLoop = this.Str.ImportSettings.LoopParsers[ImportSettings.LoopParserTypes.ByWords];

                this.CheckForLoopByAmountOfTime(writer, document, rect, timeCode);
                this.CheckForLoopByAmountOfWords(writer, document, rect, timeCode, word, doNotZigZag);

                if ( isScriptLastWord && (this.WordCount < wordsForLoop) )
                {
                    this.Str.DrawLoopBoundaryLine(this.Str.Writer, this.Str.Document, rect, true);

                    var currentYPos = this.Str.LastLoopBoundaryDrawed.IsNull() ? this.Str.Writer.GetVerticalPosition(false) : this.Str.LastLoopBoundaryDrawed.PositionY;
                    this.Str.DrawLoopNumber(this.Str.Writer, this.Str.TotalLoops +1, currentYPos + 6);
                }
            }

            #endregion
        }

        public void AddDialogue(TimeCode timeCode, string character, DialogueInfo dialogueInfo, bool isLastDialogue)
        {
            if ( !this.IsRemainingSpaceAvailableForNextDialogue(dialogueInfo) )
            {
                // BUG !!
                //ESTO FALLA PORQUE ESTO SE EJECUTA ANTES DE EL OnGenericTag
                //var currentYPos = this.LastLoopBoundaryDrawed.IsNull() ? this.Writer.GetVerticalPosition(false) : this.LastLoopBoundaryDrawed.PositionY;
                //DrawLoopNumber(this.Writer, this.TotalLoops +1, currentYPos - 30);
                this.Document.NewPage();
            }

            if (this.IsFirstDialogueOnPage)
            {
                this.LoopPosition.FirstWordPosition = this.Writer.GetVerticalPosition(false);
                this.IsFirstDialogueOnPage = false;
            }

            var currentPageNumber = this.Writer.PageNumber;
            if ( !this.TimeCodes.ContainsKey(timeCode) )                    
                this.TimeCodes.Add( timeCode, currentPageNumber );

            var tc = timeCode.ToString("hh:mm:ss");

            this.AddTimeCodeAndCharacterChunks(this.Document, tc, character);
            this.AddDialogueChunk(this.Document, dialogueInfo, tc, isLastDialogue);
        }
        public void AddDialogue(TimeCode timeCode, string character, string dialogueInfo, bool isLastDialogue)
        {
            if ( !this.IsRemainingSpaceAvailableForNextDialogue(dialogueInfo) )
            {
                // BUG !!
                //ESTO FALLA PORQUE ESTO SE EJECUTA ANTES DE EL OnGenericTag
                //var currentYPos = this.LastLoopBoundaryDrawed.IsNull() ? this.Writer.GetVerticalPosition(false) : this.LastLoopBoundaryDrawed.PositionY;
                //DrawLoopNumber(this.Writer, this.TotalLoops +1, currentYPos - 30);
                this.Document.NewPage();
            }

            if (this.IsFirstDialogueOnPage)
            {
                this.LoopPosition.FirstWordPosition = this.Writer.GetVerticalPosition(false);
                this.IsFirstDialogueOnPage = false;
            }

            var currentPageNumber = this.Writer.PageNumber;
            if ( !this.TimeCodes.ContainsKey(timeCode) )                    
                this.TimeCodes.Add( timeCode, currentPageNumber );

            var tc = timeCode.ToString("hh:mm:ss");

            this.AddTimeCodeAndCharacterChunks(this.Document, tc, character);
            this.AddDialogueChunk(this.Document, dialogueInfo, tc, isLastDialogue);
        }

        private bool IsRemainingSpaceAvailableForNextDialogue(DialogueInfo dialogueInfo)
        {
            var availableSpace = this.Writer.GetVerticalPosition(false) - this.Document.BottomMargin;

            var stream = new MemoryStream();
            var document = new Document(PageSize.LETTER);
                document.SetMargins(MarginLeft, MarginRight, MarginTop, MarginBottom);
            var writer = PdfWriter.GetInstance(document, stream);
                writer.InitialLeading = InitialLeading; //spacing between lines

            document.Open();

            var initialPosition = writer.GetVerticalPosition(false);
            
            this.AddTimeCodeAndCharacterChunks(document, "{hh:mm:ss}", "{CHARACTER}");
            this.AddDialogueChunk(document, dialogueInfo);

            var finalPosition = writer.GetVerticalPosition(false);

            stream.Close();

            return ( ((initialPosition - finalPosition) + InitialLeading) <= availableSpace);
        }
        private bool IsRemainingSpaceAvailableForNextDialogue(string dialogueInfo)
        {
            var availableSpace = this.Writer.GetVerticalPosition(false) - this.Document.BottomMargin;

            var stream = new MemoryStream();
            var document = new Document(PageSize.LETTER);
                document.SetMargins(MarginLeft, MarginRight, MarginTop, MarginBottom);
            var writer = PdfWriter.GetInstance(document, stream);
                writer.InitialLeading = InitialLeading; //spacing between lines

            document.Open();

            var initialPosition = writer.GetVerticalPosition(false);
            
            this.AddTimeCodeAndCharacterChunks(document, "{hh:mm:ss}", "{CHARACTER}");
            this.AddDialogueChunk(document, dialogueInfo);

            var finalPosition = writer.GetVerticalPosition(false);

            stream.Close();

            return ( ((initialPosition - finalPosition) + InitialLeading) <= availableSpace);
        }

        private void AddTimeCodeAndCharacterChunks(Document document, string timeCode, string character)
        {
            var timeCodeChunk = new Chunk( timeCode, this.TimeCodeFont);
            var characterChunk = new Chunk(character, this.CharacterFont);

            document.Add( timeCodeChunk );
            document.Add( new Chunk( "  " ) );
            document.Add( characterChunk ) ;
            document.Add( new Chunk( Environment.NewLine) );  
        }

        // TODO => apply DRY here
        private void AddDialogueChunk(Document document, DialogueInfo dialogueInfo, string tag = null, bool isLastDialogue = false)
        {
            var chunk = default(Chunk);

            var isLineLastWord = false;
            var isDialogueLastWord = false;
            var isScriptLastWord = false;

            var buffer = String.Empty;

            var currentCharInfo = default(DialogueInfo.CharInfo);
            var nextCharInfo = default(DialogueInfo.CharInfo);

            var bufferedChars = new StringBuilder();
            var word = string.Empty;

            var isNewWord = true;
            var isWordComplete = false;

            var font = default(Font);

            for(var i=0; i < dialogueInfo.Characters.Count; i++)
            {
                currentCharInfo = dialogueInfo.Characters[i];

                if (isNewWord)
                {
                    var fontStyle = Font.NORMAL;
                    if (currentCharInfo.Bold)
                        fontStyle = Font.BOLD;
                    if (currentCharInfo.Italic)
                        fontStyle = Font.ITALIC;
                    if (currentCharInfo.Bold && currentCharInfo.Italic)
                        fontStyle = Font.BOLDITALIC;
                    font = FontFactory.GetFont("Arial", 13f, fontStyle, new BaseColor(Color.Black));
                }

                nextCharInfo = null;
                if ( i < dialogueInfo.Characters.Count -1 )
                    nextCharInfo = dialogueInfo.Characters[i+1];

                if (nextCharInfo != null && nextCharInfo.Character.Trim().Length > 0)
                {
                    isNewWord = false;
                    bufferedChars.Append(currentCharInfo.Character);
                    continue;
                }

                if (nextCharInfo == null || nextCharInfo.Character.Trim().Length == 0)
                {
                    bufferedChars.Append(currentCharInfo.Character);
                    word = bufferedChars.ToString();
                    bufferedChars = new StringBuilder();
                    isWordComplete = true;
                }

                if ( !isWordComplete )
                    continue;
             
                word = ScriptHelper.ReplaceSpecialChars(word, PdfSpecialCharAndReplacements);

                word = word.Trim();

                if (word.Length == 0)
                    continue;

                #region Parse annotations
                if (buffer.Length > 0 && !ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd))
                {
                    buffer += word;
                    continue;
                }
                if ( ScriptHelper.HasStartingAnnotation(word, this.AnnotationStart) && !ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd) )
                {
                    buffer = word;
                    continue;
                }
                if ( ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd) )
                {
                    buffer += word;
                    word = buffer;
                    buffer = String.Empty;
                }
                #endregion

                if ( chunk.IsNotNull() )
                    document.Add( new Chunk(" ") );

                chunk = new Chunk( word, font );

                if ( tag.IsNotNull() )
                {
                    if (i == dialogueInfo.Characters.Count -1)
                    {
                        isDialogueLastWord = true;
                        if (isLastDialogue)
                            isScriptLastWord = true;
                    }
                    chunk.SetGenericTag( String.Format("{0}|{1}|{2}|{3}|{4}", word, tag, isLineLastWord, isDialogueLastWord, isScriptLastWord ) );
                }

                document.Add( chunk );

                word = String.Empty;
                isWordComplete = false;
                isNewWord = true;
            }
            document.Add( new Chunk( Environment.NewLine) );
        }
        private void AddDialogueChunk(Document document, string dialogueInfo, string tag = null, bool isLastDialogue = false)
        {
            var words = dialogueInfo.Split(' ');
            var chunk = default(Chunk);

            var isLineLastWord = false;
            var isDialogueLastWord = false;
            var isScriptLastWord = false;

            var buffer = String.Empty;

            for(var i=0; i < words.Length; i++)
            {
                var word = words[i];

                word = ScriptHelper.ReplaceSpecialChars(word, PdfSpecialCharAndReplacements);

                if (word.Trim().Length <= 0)
                    continue;

                #region Parse annotations
                if (buffer.Length > 0 && !ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd))
                {
                    buffer += word;
                    continue;
                }
                if ( ScriptHelper.HasStartingAnnotation(word, this.AnnotationStart) && !ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd) )
                {
                    buffer = word;
                    continue;
                }
                if ( ScriptHelper.HasEndingAnnotation(word, this.AnnotationEnd) )
                {
                    buffer += word;
                    word = buffer;
                    buffer = String.Empty;
                }
                #endregion

                if ( chunk.IsNotNull() )
                    document.Add( new Chunk(" ") );

                chunk = new Chunk( word, this.DialogueFont );

                if ( tag.IsNotNull() )
                {
                    if (i == words.Length -1)
                    {
                        isDialogueLastWord = true;
                        if (isLastDialogue)
                            isScriptLastWord = true;
                    }
                    chunk.SetGenericTag( String.Format("{0}|{1}|{2}|{3}|{4}", word, tag, isLineLastWord, isDialogueLastWord, isScriptLastWord ) );
                }

                document.Add( chunk );
            }         
            document.Add( new Chunk( Environment.NewLine) );
        }

        // TODO => apply DRY here
        private void DrawLoopBoundaryLine(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect, bool doNotZigZag = false, float offsetX = 0)
        {
            // SetLineDash
            // (5)       => _____________
            // (8, 8, 8) => ___ ____ ____ 
            // (2, 2, 2) => _ _ _ _ _ _ _ 

            var pdfContentByte = writer.DirectContent;
                pdfContentByte.SaveState();
                pdfContentByte.SetLineWidth(0.5f);
                pdfContentByte.SetLineDash(4, 4);
                pdfContentByte.MoveTo(document.Left - MarginLeft, rect.Bottom - OffsetBottom);
                pdfContentByte.LineTo(rect.Right + OffsetLeft + OffsetRight + offsetX, rect.Bottom - OffsetBottom);
                if (doNotZigZag)
                {
                    pdfContentByte.LineTo(document.Right + 2 + MarginRight, rect.Bottom - OffsetBottom);
                }
                else
                {
                    pdfContentByte.LineTo(rect.Right + OffsetLeft + OffsetRight + offsetX, rect.Top + OffsetTop );
                    pdfContentByte.LineTo(document.Right + 2 + MarginRight, rect.Top + OffsetTop);
                }
                pdfContentByte.Stroke();
                pdfContentByte.RestoreState();

            this.UpdateLastLoopBoundaryLine( document.Left - MarginLeft, rect.Bottom - OffsetBottom );
        }
        private void DrawLoopBoundaryLine2(PdfWriter writer, Document document, iTextSharp.text.Rectangle rect)
        {
            var pdfContentByte = writer.DirectContent;
                pdfContentByte.SaveState();
                pdfContentByte.SetLineWidth(0.5f);
                pdfContentByte.SetLineDash(4, 4);
                pdfContentByte.MoveTo(document.Left - MarginLeft, rect.Top + OffsetTop + 30);
                pdfContentByte.LineTo(document.Right + 2 + MarginRight, rect.Top + OffsetTop + 30);
                pdfContentByte.Stroke();
                pdfContentByte.RestoreState();

            this.UpdateLastLoopBoundaryLine( document.Left - MarginLeft, rect.Top + OffsetTop + 30 );
        }

        // TODO => apply DRY here
        private void DrawLoopNumber(PdfWriter writer, int loopNumber, float positionTop, float positionBottom, bool isTimeReached = false)
        {
            var xPos = 0f;
            var yPos = 0f;

            if (this.LastLoopBoundariesDrawed != null && this.LastLoopBoundariesDrawed.Count > 1 && isTimeReached)
            {
                var lastBoundary = this.LastLoopBoundariesDrawed[this.LastLoopBoundariesDrawed.Count - 2];

                positionTop = lastBoundary.PositionY;

                var currentPageNumber = this.GetCurrentPageNumber();
                if (lastBoundary.PageNumber != currentPageNumber)
                {
                    positionTop = this.Document.PageSize.Top;
                }

                xPos    = LoopNumberXPos;
                yPos    = (positionTop - ((positionTop - positionBottom)/2)) + (OffsetBottom*2);
            }
            else
            {
                xPos    = LoopNumberXPos;
                yPos    = (positionTop - ((positionTop - positionBottom)/2)) - (OffsetBottom*2);
            }

            var pdfContentByte = writer.DirectContent;
                pdfContentByte.BeginText();
                pdfContentByte.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 22);
                pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, loopNumber.ToString(), xPos, yPos, 0);
                pdfContentByte.EndText();            
        }
        private void DrawLoopNumber(PdfWriter writer, int loopNumber, float yPos)
        {
            var xPos    = LoopNumberXPos;

            var pdfContentByte = writer.DirectContent;
                pdfContentByte.BeginText();
                pdfContentByte.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 22);
                pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, loopNumber.ToString(), xPos, yPos, 0);
                pdfContentByte.EndText();            
        }

        private void UpdateLastLoopBoundaryLine(float xPos, float yPos)
        {
            var currentPageNumber = GetCurrentPageNumber();

            this.LastLoopBoundaryDrawed = new LoopBoundaryLineInfo { PositionX = xPos, PositionY = yPos, PageNumber = currentPageNumber };

            if ( this.LastLoopBoundariesDrawed == null )
                this.LastLoopBoundariesDrawed = new List<LoopBoundaryLineInfo>();

            this.LastLoopBoundariesDrawed.Add( this.LastLoopBoundaryDrawed );
        }

        private int GetCurrentPageNumber()
        {
            return this.Writer.PageNumber;
        }
    }
}